package router

import (
	"io/fs"
	"path/filepath"
	"plugin"
	"reflect"
	"strings"

	"gitee.com/war2001/NiuMaEasyGo/model"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// ControllerRegistry 控制器注册表
type ControllerRegistry struct {
	controllers      []interface{}
	db               *gorm.DB
	routeMetadataMap map[string]RouteMetadata
}

// NewControllerRegistry 创建控制器注册表
func NewControllerRegistry(db *gorm.DB) *ControllerRegistry {
	return &ControllerRegistry{
		controllers:      make([]interface{}, 0),
		db:               db,
		routeMetadataMap: make(map[string]RouteMetadata),
	}
}

// RegisterController 注册单个控制器
func (r *ControllerRegistry) RegisterController(controller interface{}) {
	r.controllers = append(r.controllers, controller)
}

// AutoDiscoverControllers 自动发现并注册控制器
// 通过反射机制扫描指定目录下的所有Go文件，查找控制器类型并注册
func (r *ControllerRegistry) AutoDiscoverControllers(controllerDir string, services interface{}) error {
	// 遍历目录
	err := filepath.WalkDir(controllerDir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		// 只处理Go文件
		if !d.IsDir() && strings.HasSuffix(d.Name(), ".go") && !strings.HasSuffix(d.Name(), "_test.go") {
			// 尝试加载文件作为插件（仅在支持插件的平台上可用）
			// 这里仅作为示例，实际可能需要其他方式实现
			if p, err := plugin.Open(path); err == nil {
				// 查找New*Controller函数
				for _, prefix := range []string{"New", "Create"} {
					for _, suffix := range []string{"Controller", "API", "Handler"} {
						symbolName := prefix + "*" + suffix
						if sym, err := p.Lookup(symbolName); err == nil {
							// 尝试调用函数创建控制器实例
							if constructor, ok := sym.(func() interface{}); ok {
								controller := constructor()
								r.RegisterController(controller)
								zap.L().Info("自动发现并注册控制器",
									zap.String("file", d.Name()),
									zap.String("controller", reflect.TypeOf(controller).String()))
							}
						}
					}
				}
			}
		}
		return nil
	})

	return err
}

// RegisterRoutes 将所有注册的控制器注册到路由
func (r *ControllerRegistry) RegisterRoutes(engine *gin.Engine, apiPrefix string) {
	// 创建API路由组
	apiGroup := engine.Group(apiPrefix)

	// 遍历所有注册的控制器
	for _, controller := range r.controllers {
		// 检查控制器类型
		controllerType := reflect.TypeOf(controller)
		controllerValue := reflect.ValueOf(controller)

		// 查找RegisterRoutes方法（旧方式兼容）
		if method, ok := controllerType.MethodByName("RegisterRoutes"); ok {
			// 调用RegisterRoutes方法
			args := []reflect.Value{controllerValue, reflect.ValueOf(apiGroup)}
			method.Func.Call(args)
			continue
		}

		// 使用新方式注册（基于元数据）
		routerGroup := NewRouterGroup(apiGroup, r.db, r)
		routerGroup.RegisterController(controller)
	}
}

// ControllerRouterGroup 是Router的包装，用于控制器注册
type ControllerRouterGroup struct {
	*gin.RouterGroup
	router   *Router
	registry *ControllerRegistry
}

// NewRouterGroup 创建路由组
func NewRouterGroup(group *gin.RouterGroup, db *gorm.DB, registry *ControllerRegistry) *ControllerRouterGroup {
	router := &Router{
		Engine:           nil, // 不需要Engine
		RouteMetadataMap: make(map[string]RouteMetadata),
		DB:               db,
	}

	return &ControllerRouterGroup{
		RouterGroup: group,
		router:      router,
		registry:    registry,
	}
}

// RegisterController 注册控制器
func (g *ControllerRouterGroup) RegisterController(controller interface{}) {
	controllerType := reflect.TypeOf(controller)
	controllerValue := reflect.ValueOf(controller)

	// 遍历控制器的方法
	for i := 0; i < controllerType.NumMethod(); i++ {
		method := controllerType.Method(i)

		// 检查方法是否有元数据函数
		metadataFuncName := method.Name + "Metadata"
		metadataMethod, exists := controllerType.MethodByName(metadataFuncName)

		if exists {
			// 调用元数据函数获取路由元数据
			metadataValues := metadataMethod.Func.Call([]reflect.Value{controllerValue})
			if len(metadataValues) > 0 {
				metadata, ok := metadataValues[0].Interface().(RouteMetadata)
				if ok {
					// 获取处理函数
					handlerFunc := controllerValue.Method(i).Interface().(func(*gin.Context))

					// 注册路由
					switch metadata.Method {
					case "GET":
						g.GET(metadata.APIPath, handlerFunc)
					case "POST":
						g.POST(metadata.APIPath, handlerFunc)
					case "PUT":
						g.PUT(metadata.APIPath, handlerFunc)
					case "DELETE":
						g.DELETE(metadata.APIPath, handlerFunc)
					case "PATCH":
						g.PATCH(metadata.APIPath, handlerFunc)
					case "OPTIONS":
						g.OPTIONS(metadata.APIPath, handlerFunc)
					case "HEAD":
						g.HEAD(metadata.APIPath, handlerFunc)
					default:
						g.GET(metadata.APIPath, handlerFunc)
					}

					// 存储路由元数据
					key := g.BasePath() + metadata.APIPath
					g.router.RouteMetadataMap[key] = metadata
					// 同时存储到注册表中
					g.registry.routeMetadataMap[key] = metadata

					zap.L().Debug("注册路由",
						zap.String("method", metadata.Method),
						zap.String("path", metadata.APIPath),
						zap.String("controller", controllerType.String()),
						zap.String("handler", method.Name))
				}
			}
		}
	}
}

// GenerateMenus 根据路由元数据生成菜单
func (r *ControllerRegistry) GenerateMenus() []*model.SysMenu {
	zap.L().Info("开始生成菜单", zap.Int("路由元数据数量", len(r.routeMetadataMap)))

	menuMap := make(map[string]*model.SysMenu)
	menuList := make([]*model.SysMenu, 0)

	// 第一步：创建所有目录和菜单
	for path, metadata := range r.routeMetadataMap {
		zap.L().Debug("处理路由元数据",
			zap.String("path", path),
			zap.String("title", metadata.Title),
			zap.String("menuType", metadata.MenuType),
			zap.String("menuCategory", metadata.MenuCategory))
		// 跳过按钮类型
		if metadata.MenuType == "button" {
			continue
		}

		// 创建菜单对象
		menu := &model.SysMenu{
			Name:         metadata.Title,
			Path:         metadata.Path,
			Component:    metadata.Component,
			Permission:   metadata.Permission,
			Type:         metadata.MenuType,
			Icon:         metadata.Icon,
			OrderNum:     metadata.OrderNum,
			Hidden:       metadata.Hidden,
			KeepAlive:    metadata.KeepAlive,
			AlwaysShow:   metadata.AlwaysShow,
			MenuCategory: metadata.MenuCategory,
		}

		// 添加到映射表和列表中
		menuMap[metadata.Path] = menu
		menuList = append(menuList, menu)
	}

	// 第二步：建立父子关系
	for _, menu := range menuList {
		for _, metadata := range r.routeMetadataMap {
			if metadata.Path == menu.Path && metadata.ParentPath != "" {
				if parent, ok := menuMap[metadata.ParentPath]; ok {
					menu.ParentID = uint64(parent.ID)
				}
			}
		}
	}

	// 第三步：添加按钮权限
	for _, metadata := range r.routeMetadataMap {
		if metadata.MenuType == "button" && metadata.ParentPath != "" {
			if parent, ok := menuMap[metadata.ParentPath]; ok {
				button := &model.SysMenu{
					ParentID:     uint64(parent.ID),
					Name:         metadata.Title,
					Path:         "",
					Component:    "",
					Permission:   metadata.Permission,
					Type:         "button",
					Icon:         metadata.Icon,
					OrderNum:     metadata.OrderNum,
					Hidden:       metadata.Hidden,
					MenuCategory: metadata.MenuCategory,
				}
				menuList = append(menuList, button)
			}
		}
	}

	zap.L().Info("菜单生成完成", zap.Int("生成菜单数量", len(menuList)))
	return menuList
}
